/**
 * 结构体定义和使用: https://www.bilibili.com/video/BV1vs411n7TH?p=103
 * 结构体(Java的对象), 定义:
 *  struct [结构体名] {     //1.结构体类型名(类型名 可不写)
 *      char name[21];     //2.成员列表
 *      int age;
 *  } [st1],               //3.结构体变量名(变量名 可不写)
 *  st2 = {"张三", ...};    //4.定义后, 直接实例化一个对象
 *
 *
 * struct 结构体名 st3;             //5.可手动定义结构体变量, 然后依次赋值
 *
 * struct Student stu2 = {"李四", ...};   //6.手动定义变量&直接赋值
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../entity/Student.h"          //导入结构体!!!
#include "../entity/Student_Pointer.h"

struct Student;

void struct_sizeof();
void struct_value();
void struct_array();
void struct_sort();
void struct_malloc();
void struct_struct();
void struct_pointer();
void struct_pointer_edit();
void struct_pointer_param_edit();
void struct_array_pointer_sort();
void const_struct();

int main() {
    //1.sizeof
    struct_sizeof();
    //2.结构体声明&赋值
    struct_value();
    //3.结构体数组
    struct_array();
    //4.结构体排序
    struct_sort();
    //5.结构体 开辟堆空间
    struct_malloc();
    //6.结构体 嵌套 结构体
    struct_struct();
    //7.结构体 & 指针
    struct_pointer();
    //8.结构体内 成员指针 修改
    struct_pointer_edit();
    //9.结构体指针 作为参数 传递
    struct_pointer_param_edit();
    //10.结构体数组 传指针 排序
    struct_array_pointer_sort();
    //11.const 修饰的结构体 指针
    const_struct();

    return EXIT_SUCCESS;
}

/**
 * ∵结构体成员需要偏移'内存对齐', ∴
 */
void struct_sizeof() {
    struct Student stu1;
    printf("sizeof(stu1) = %d\n", sizeof(stu1));                    //36
    printf("sizeof(struct Student) = %d\n", sizeof(struct Student));//36
}

//1.结构体声明&赋值
void struct_value() {
    /**
     * 1.先声明, 再赋值
     */
    struct Student stu1;
//    stu1.name = "张三";      //stu.name常量, 不可赋值
//    stu1.name[0] = 'a';     //这种方式也可以, 不过汉字赋值不进去
    strcpy(stu1.name, "张三");
    stu1.sex = '1';
    stu1.age = 23;
    stu1.score[0] = 100;
    stu1.score[1] = 99;
    stu1.pstudy = &study;     //给函数指针赋值 = study()方法的指针
    printf("1.结构体声明&赋值\n");
    printStudent(stu1);

    /**
     * 2.声明的时候就赋值
     *                            .age 可指定成员赋值      score[2] 可加{}, 也可不加. 建议加上
     */
    struct Student stu2 = {"李四", .age = 24, .sex = '1', .score = {99, 100} };
    printStudent(stu2);
}

//2.结构体数组
void struct_array() {
    struct Student stus[] = {
            {"张三", '1', 23, 100, 99 },
            {"李四", '1', 24, {99, 100}}
    };
    printf("2.结构体数组\n");
    for (int i = 0; i < 2; ++i) {
        struct Student stu = stus[i];
        printStudent(stu);
    }
}

//3.结构体排序
void struct_sort() {
    struct Student stus[] = {
            {"张三", '1', 23, 100, 99 },
            {"李四", '1', 24, {99, 100}},
            {"王五", '1', 18, {99, 88}}
    };
    //冒泡排序
    for (int i = 0; i < 3 - 1; ++i) {
        for (int j = 0; j < 3 - i - 1; ++j) {
            if (stus[j].age > stus[j + 1].age) {
                struct Student temp = stus[j];
                stus[j] = stus[j + 1];
                stus[j + 1] = temp;
            }
        }
    }
    printf("3.结构体排序\n");
    for (int i = 0; i < 3; ++i) {
        struct Student stu = stus[i];
        printStudent(stu);
    }
}

//5.结构体 开辟堆空间
void struct_malloc() {
    size_t size = sizeof(struct Student);
    struct Student *stu = malloc(size * 3);
    free(stu);
}

//6.结构体 嵌套 结构体
void struct_struct() {
    struct PayRecord {              //消费记录
        double money;
        long time;
        int id;
    };
    struct BankCard {               //银行卡
        char cardId[25];
        char password[6];
        struct PayRecord payRecord; //结构体嵌套
    };
    //初始化
    struct BankCard card = {"123123123", "123456", {12.3F, 1231313123L, 1} };
    struct PayRecord rc = card.payRecord;
    printf("6.结构体 嵌套 结构体: cardId=%s, password=%s, payRecord={%lf, %ld, %d}\n", card.cardId, card.password, rc.money, rc.time, rc.id);
}

//7.结构体 & 指针 https://www.bilibili.com/video/BV1vs411n7TH?p=108
void struct_pointer() {
    struct Student stu0 = {"张三", '1', 23, {66, 77}};
    struct Student stu1 = stu0;
    struct Student *p0 = &stu0;     //结构体指针
    char *name0 = (*p0).name;
    char *name1 = p0->name;         //结构体指针(对象)->成员
//    printStudentExtra("7.结构体 & 指针: ", *p0);

    struct Student_Pointer *p2 = malloc(sizeof(stu0) * 3);//一次性开辟3个!!
    for (int i = 0; i < 3; ++i) {
        p2[i].name = (char*)malloc(sizeof(char) * 21);
        p2[i].age = 25 + i;
        (p2+i)->score = malloc(sizeof(int) * 2);
        strcpy(p2[i].name,  "张三");
        p2[i].score[0] = 66 + i * 3;
        p2[i].score[1] = 66 + i * 5;
    }
    for (int i = 0; i < 3; ++i) {
        struct Student_Pointer *stu = p2 + i;
        printStudentPointerExtra("结构体里的成员 是指针:", stu);
    }
    //释放
    for (int i = 0; i < 3; ++i) {
        struct Student_Pointer *stu = p2 + i;
        free(stu->name);
        free(stu->score);
    }
    free(p2);
}

//8.结构体内 成员指针 修改
void edit(struct Student_Pointer);
void struct_pointer_edit() {
    struct Student_Pointer stu = {"a", 23, NULL};
    stu.name = malloc(sizeof(char) * 21);
    strcpy(stu.name, "张三");
    printf("8.结构体指针修改: name = %s\n", stu.name);//张三
    edit(stu);
    printf("name = %s\n", stu.name);                //李四  ∵name是指针, ∴edit()能修改
    free(stu.name);
}
void edit(struct Student_Pointer stu) {
    strcpy(stu.name, "李四");
}

//9.结构体指针 作为参数 传递
void edit2(struct Student_Pointer *p);
void struct_pointer_param_edit() {
    struct Student_Pointer stu = {"a", 23, NULL};
    stu.name = malloc(sizeof(char) * 21);
    strcpy(stu.name, "张三");
    printf("9.结构体指针 作为参数 传递: name = %s\n", stu.name);//张三
    edit2(&stu);
    printf("name = %s\n", stu.name);        //李四
    free(stu.name);
}
void edit2(struct Student_Pointer *p) {
    strcpy(p->name, "李四");
}

//10.结构体数组 传指针 排序
void BubbleSort(struct Student stus[], int len);
void struct_array_pointer_sort() {
    struct Student stus[3] = {
            {"王五", '0', 25, {22, 33}},
            {"张三", '1', 23, {44, 55}},
            {"李四", '1', 24, {66, 77}}
    };
    BubbleSort(stus, 3);
    printf("10.结构体数组 排序\n");
    for (int i = 0; i < 3; ++i) {
        struct Student stu = stus[i];
        printStudent(stu);
    }
}
void BubbleSort(struct Student *stus, int len) {
    for (int i = 0; i < len - 1; ++i) {
        for (int j = 0; j < len - i - 1; ++j) {
            if (stus[j].age > stus[j + 1].age) {
                struct Student temp = stus[j];
                stus[j] = stus[j + 1];
                stus[j + 1] = temp;
            }
        }
    }
}

//11.const 修饰的结构体 指针 https://www.bilibili.com/video/BV1vs411n7TH/?p=108
void const_struct() {
    struct Student stu0 = {"张三", '1', 23, {55, 66}};
    struct Student stu1 = {"李四", '1', 24, {77, 88}};

    const struct Student *p0 = &stu0;   //const修饰 Student
//    p0->age = 25;                     //✘
    p0 = &stu1;                         //✔

    struct Student *const p1 = &stu0;   //const修饰 指针变量
    p1->age = 25;                       //✔
//    p1 = &stu1;                       //✘

    const struct Student *const p2 = &stu0;//const修饰 Student & 指针变量
//    p2->age = 25;                     //✘
//    p2 = &stu1;                       //✘

    struct Student **pp = (struct Student **) &p2;  //可通过2级指针修改
    (*pp)->age = 26;
    printf("11.const 修饰的结构体 指针\n");
    printStudent(**pp);
}

